import streamlit as st
import streamlit_antd_components as sac
import ujson as json
import sys
from code_editor import code_editor
from data_utils import code_save_button_config
import matplotlib.pyplot as plt
from .menu_manager import MenuManager
from data_utils import load_calculators, save_calculator
from admin.calculator_utils import (
    edit_calc_page,
    ensure_target_field,
    sort_targets,
    render_input_field,
    execute_calculator,
    status_colors,
    status_icon,
)

# 设置matplotlib全局字体
if sys.platform.startswith("win"):
    plt.rcParams["font.family"] = "SimHei"
elif sys.platform.startswith("linux"):
    plt.rcParams["font.family"] = "WenQuanYi Micro Hei"
elif sys.platform.startswith("darwin"):
    plt.rcParams["font.family"] = "Heiti TC"

# 配置其他全局字体设置
plt.rcParams["axes.unicode_minus"] = False  # 正确显示负号
plt.rcParams["font.size"] = 12  # 设置默认字体大小


def load_calculator_guide():
    """从文件加载计算器编写指南"""
    guide_path = "docs/calculator_guide.md"
    try:
        with open(guide_path, "r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        return """# 加载指南失败
请检查 docs/calculator_guide.md 文件是否存在。
"""

def calculator_management():
    """计算器管理页面"""
    # st.subheader("计算器管理")

    # 新增状态控制
    # if "show_add_calc" not in st.session_state:
    #     st.session_state.show_add_calc = False

    # "新增计算器"按钮 - 仅计算器管理员和系统管理员可见
    if any(role in st.session_state.roles for role in ["calcadmin", "sysadmin"]):
        menu_manager = MenuManager.get_instance()

        # 加载所有计算器并按更新时间降序排序
        all_calcs = load_calculators()
        sorted_calcs = sorted(all_calcs, key=lambda calc: calc.updated_at, reverse=True)

        # 在侧边栏增加下拉框
        selected = st.sidebar.selectbox(
            "选择管理的计算器",
            options=["最近的计算器"] + [calc.name for calc in sorted_calcs],
            key="selected_calc",
        )
        # 若选中具体计算器，则跳转到编辑页面
        if selected != "最近的计算器":
            for calc in sorted_calcs:
                if calc.name == selected:
                    edit_calc_page(calc.id)
                    return  # 直接返回，不再注册其他菜单项
            # 若未找到对应计算器则还原为全部显示
        # 分割线和父菜单注册
        menu_manager.register("add_calc_divider", lambda: None, type="divider")
        menu_manager.register(
            "calculator_management",
            lambda: None,  # 父菜单不需要处理函数
            label="最近的计算器",
            type="group",
            children=[],  # 先创建空的子菜单列表
        )

        menu_manager.register(
            "add_calc",
            lambda: add_calc_page(),
            label="新增计算器",
            icon="plus-circle-fill",
            parent="calculator_management",  # 指定父菜单
        )

        # 只注册最近修改过的5个计算器
        recent_calcs = sorted_calcs[:5]
        for calc in recent_calcs:
            menu_manager.register(
                f"edit_calc_{calc.id}",
                lambda cid=calc.id: edit_calc_page(cid),
                label=calc.name,
                icon="calculator-fill",
                parent="calculator_management",  # 指定父菜单
                tag=[
                    sac.Tag(
                        "",
                        color=status_colors.get(calc.status, "blue"),
                        icon=status_icon.get(
                            calc.status, sac.BsIcon(name="question-lg")
                        ),
                    )
                ],
            )


def add_calc_page():
    """新增计算器"""
    st.subheader("新增计算器")

    # 添加取消按钮
    # if st.button("⬅️ 返回计算器列表"):
    #     # st.session_state.show_add_calc = False
    #     # st.session_state.selected_add = False
    #     st.rerun()

    with st.expander("代码编写规范与安全提示", expanded=False):
        st.markdown(load_calculator_guide())

    # 用于选择编辑 JSON Schema 的方式
    schema_mode = st.radio(
        "选择编辑输入参数的方式", ["图形界面", "JSON模式"], key="add_schema_mode"
    )

    if schema_mode == "JSON模式":
        default_json = """[
  {
    "name": "A1",
    "title": "单价",
    "type": "number",
    "target": "价格信息",
    "minimum": 0.00,
    "maximum": 999999.99,
    "step": 0.01,
    "default": 100.00,
    "input_mode": "输入项"
  },
  {
    "name": "A2",
    "title": "数量",
    "type": "integer",
    "target": "价格信息",
    "minimum": 1,
    "maximum": 9999,
    "step": 1,
    "default": 1,
    "input_mode": "输入项"
  },
  {
    "name": "discount",
    "title": "折扣",
    "type": "number",
    "target": "折扣信息",
    "minimum": 0.1,
    "maximum": 1.0,
    "step": 0.01,
    "default": 1.0,
    "input_mode": "输入项"
  }
]"""
        input_str = st.text_area(
            "输入参数配置（JSON数组）",
            value=default_json,
            height=150,
            key="add_input_str_json",
        )

        # 修改刷新按钮逻辑，改用 session_state 存储状态
        if st.button("刷新输入输出 (新增)", key="refresh_json_inputs"):
            try:
                st.session_state["add_parsed_inputs"] = json.loads(input_str)
                st.rerun()
            except Exception as e:
                st.error(f"解析 JSON 失败：{e}")

        if "add_parsed_inputs" not in st.session_state:
            try:
                inputs = json.loads(input_str)
                st.session_state["add_parsed_inputs"] = ensure_target_field(inputs)
            except:
                st.session_state["add_parsed_inputs"] = []
        parsed_inputs = st.session_state["add_parsed_inputs"]
    else:
        if "add_parsed_inputs" not in st.session_state:
            st.session_state["add_parsed_inputs"] = [
                {
                    "name": "A1",
                    "title": "单价",
                    "type": "number",
                    "target": "价格信息",
                    "minimum": 0.00,
                    "maximum": 999999.99,
                    "step": 0.01,
                    "default": 100.00,
                    "input_mode": "输入项",
                },
                {
                    "name": "A2",
                    "title": "数量",
                    "type": "integer",
                    "target": "价格信息",
                    "minimum": 1,
                    "maximum": 9999,
                    "step": 1,
                    "default": 1,
                    "input_mode": "输入项",
                },
                {
                    "name": "discount",
                    "title": "折扣",
                    "type": "number",
                    "target": "折扣信息",
                    "minimum": 0.1,
                    "maximum": 1.0,
                    "step": 0.01,
                    "default": 1.0,
                    "input_mode": "输入项",
                },
            ]

        # 添加 target 列的配置
        column_config = {
            "name": "变量名",
            "title": "标题",
            "input_mode": st.column_config.SelectboxColumn(
                "输入类型", options=["输入项", "非输入项"], default="输入项"
            ),
            "type": st.column_config.SelectboxColumn(
                "数据类型", options=["number", "integer", "string"], default="string"
            ),
            "target": "计算对象",
            "minimum": "最小值",
            "maximum": "最大值",
            "step": "有效位数",
            "default": "默认值",
        }

        data_editor_value = st.data_editor(
            st.session_state["add_parsed_inputs"],
            key="add_data_editor",
            use_container_width=True,
            num_rows="dynamic",
            column_config=column_config,
        )
        if st.button("刷新输入输出 (新增)", key="refresh_editor_inputs"):
            st.session_state["add_parsed_inputs"] = data_editor_value
            st.rerun()

        parsed_inputs = st.session_state["add_parsed_inputs"]

    with st.form("add_calc_form"):
        name = st.text_input("计算器名称")
        st.write("计算公式")
        code = code_editor(
            code="""# 示例: Excel风格计算和图表输出
sheet['A3'].value = discount  # 折扣率

# 使用Excel公式计算
sheet['B1'].formula = '=A1*A2'  # 总价
sheet['B2'].formula = '=B1*A3'  # 折后价

# 准备数据并绘制图表
labels = ['原价', '折后价']
values = [sheet['B1'].value, sheet['B2'].value]

plt.figure(figsize=(8, 4))
plt.bar(labels, values)
plt.title('价格对比')
plt.ylabel('总价(元)')

# 返回多个结果
result = [
    f"总价: {sheet['B1'].value:.2f}元",
    f"折后价: {sheet['B2'].value:.2f}元"
]""",
            height=20,
            response_mode="debounce",
            lang="python",
            buttons=code_save_button_config,
        )["text"]

        st.write("#### 测试输入")
        test_inputs = {}

        # 收集所有不同的 target，并创建 tabs
        targets = set()
        for inp in parsed_inputs:
            target = inp.get("target", "其他")
            targets.add(target)

        input_fields_by_target = {}
        for inp in parsed_inputs:
            target = inp.get("target", "其他")
            if target is None:
                target = "其他"
            if target not in input_fields_by_target:
                input_fields_by_target[target] = []
            input_fields_by_target[target].append(inp)

        # 如果只有一个 target，不创建 tabs
        if len(targets) <= 1:
            # 修改为每行两个输入字段
            fields = parsed_inputs
            for i in range(0, len(fields), 2):
                col1, col2 = st.columns(2)
                # 渲染第一个字段
                render_input_field(fields[i], test_inputs, col1)
                # 如果有第二个字段，渲染它
                if i + 1 < len(fields):
                    render_input_field(fields[i + 1], test_inputs, col2)
        else:
            # 筛选出有效的 target 和对应的字段
            valid_targets = {}
            for target in sort_targets(targets):
                # 获取当前 target 的所有字段
                target_fields = input_fields_by_target[target]
                # 筛选出 input_mode 不是"非输入项"的字段
                valid_fields = [
                    field
                    for field in target_fields
                    if field.get("input_mode") != "非输入项"
                ]
                # 只有当有可显示的字段时，才将该 target 加入到有效列表中
                if valid_fields:
                    valid_targets[target] = valid_fields

            # 只为有效的 target 创建 tabs
            if valid_targets:
                input_group_tabs = st.tabs(list(valid_targets.keys()))
                # 在每个 tab 中显示对应的输入字段
                for i, target in enumerate(valid_targets.keys()):
                    with input_group_tabs[i]:
                        # 使用已筛选的有效字段
                        target_fields = valid_targets[target]

                        # 创建足够的行来容纳所有字段
                        for j in range(0, len(target_fields), 2):
                            col1, col2 = st.columns(2)
                            # 渲染第一个字段
                            render_input_field(target_fields[j], test_inputs, col1)
                            # 如果有第二个字段，渲染它
                            if j + 1 < len(target_fields):
                                render_input_field(
                                    target_fields[j + 1], test_inputs, col2
                                )

        btn_test = st.form_submit_button("测试运行 (新增)")
        btn_save = st.form_submit_button("保存计算器 (新增)")

        if btn_test:
            calc_result, success = execute_calculator(code, test_inputs, st)
            if success:
                st.toast("测试成功!")

        if btn_save:
            new_calc = {
                "name": name,
                "code": code,
                "inputs": ensure_target_field(parsed_inputs),
                "access_control": {
                    "type": "all",  # "all" 或 "restricted"
                    "allowed_users": [],  # 当 type 为 "restricted" 时生效
                },
                "status": "draft",
            }
            try:
                db_calc = save_calculator(new_calc)
                st.toast(f"已创建新计算器：{name}")
            except Exception as e:
                import traceback

                traceback.print_exc()
                st.error(f"保存计算器时出错：{e}")
            st.rerun()
